package com.uduemc.biso.node.web.scheduled;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageInfo;
import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.node.core.entities.HDomain;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.SitePathUtil;
import com.uduemc.biso.node.web.api.service.DomainService;
import com.uduemc.biso.node.web.api.service.HostService;
import com.uduemc.biso.node.web.component.NginxOperate;
import com.uduemc.biso.node.web.component.NginxServer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Component
@Slf4j
public class NginxScheduled {

    @Resource
    private NginxOperate nginxOperate;

    @Resource
    private NginxServer nginxServer;

    @Resource
    private HostService hostServiceImpl;

    @Resource
    private DomainService domainServiceImpl;

    @Resource
    private GlobalProperties globalProperties;

//	@Autowired
//	private SpringContextUtil springContextUtil;


//	/**
//	 * 每5秒钟
//	 */
//	@Scheduled(cron = "*/5 * * * * ?")

    /**
     * 每天0点执行对所有站点的Nginx日志进行切割
     */
    @Async
    @Scheduled(cron = "0 0 0 * * ?")
    void logCut() {

        // 首先测试 nginx 测试是否正常，如果异常记录日志且，不再执行后续。
        if (!nginxTest()) {
            log.error("NginxScheduled.logCut() 初始执行 Nginx 测试异常。");
            return;
        }

        // 删除host下绑定域名以外的Nginx日志，包含备份日志记录文件夹，同时获取到所有绑定域名的日志地址
        List<HostBindDomainData> doList = new ArrayList<>();
        cleanOtherHostBindDomainNginxLog(doList);

        if (CollUtil.isEmpty(doList)) {
            return;
        }

        // 测试 nginx 测试是否正常，如果异常记录日志且，不再执行后续。
        if (!nginxTest()) {
            log.error("NginxScheduled.logCut() 开始切割执行 Nginx 测试异常。");
            return;
        }

        // 每切割一个nginx配置后，测试是否正常，如果异常记录日志且，不再执行后续。
        // 批量获取用户绑定域名

//		List<Host> listHost = new ArrayList<>();

        // 切割完毕所有的日志后，测试是否正常，如果异常记录日志且，不再执行后续。
        if (!nginxTest()) {
            log.error("NginxScheduled.logCut() 切割完毕执行 Nginx 测试异常。");
            return;
        }

        // 最后重启nginx
        nginxReload();
    }

    /**
     * 首先清除所有Host绑定域名的
     */
    void cleanOtherHostBindDomainNginxLog(List<HostBindDomainData> doList) {
        makeHostBindDomainDataList(doList);
        if (CollUtil.isEmpty(doList)) {
            return;
        }

        for (HostBindDomainData hostBindDomainData : doList) {
            List<String> logFilePath = hostBindDomainData.logFilePath();
            String logFilePathRoot = SitePathUtil.getUserNginxlogPathByCode(globalProperties.getSite().getBasePath(),
                    hostBindDomainData.getHost().getRandomCode());
            File[] parentPathLs = FileUtil.ls(logFilePathRoot);
            if (ArrayUtil.isNotEmpty(parentPathLs)) {
                if (CollUtil.isEmpty(logFilePath)) {
                    for (File nginxLogFile : parentPathLs) {
                        String name = FileUtil.getName(nginxLogFile);
                        if (name.equals(".") || name.equals("..")) {
                            continue;
                        }
                        if (FileUtil.isFile(nginxLogFile)) {
                            FileUtil.del(nginxLogFile);
                        }
                    }
                } else {
                    for (File nginxLogFile : parentPathLs) {
                        String name = FileUtil.getName(nginxLogFile);
                        if (name.equals(".") || name.equals("..")) {
                            continue;
                        }
                        if (FileUtil.isFile(nginxLogFile)) {
                            String nginxLogFileCanonicalPath = FileUtil.getCanonicalPath(nginxLogFile);
                            if (StrUtil.isNotBlank(nginxLogFileCanonicalPath)) {
                                Optional<String> findFirst = logFilePath.stream().filter(item -> {
                                    String itemCanonicalPath = FileUtil.getCanonicalPath(new File(item));
                                    if (StrUtil.isBlank(itemCanonicalPath)) {
                                        return false;
                                    }
                                    return itemCanonicalPath.equals(nginxLogFileCanonicalPath);
                                }).findFirst();
                                if (!findFirst.isPresent()) {
                                    log.warn("删除多余Nginx日志文件，nginxLogFile:" + nginxLogFile + ",hostBindDomainData:" + hostBindDomainData);
                                    FileUtil.del(nginxLogFile);
                                }
                            }
                        }
                    }
                }
            }

            List<String> historyLogDirs = hostBindDomainData.historyLogDir();
            String historyLogDirRoot = SitePathUtil.getUserNginxHistorylogPathByCode(globalProperties.getSite().getBasePath(),
                    hostBindDomainData.getHost().getRandomCode());
            File[] historyLogDirRootLs = FileUtil.ls(historyLogDirRoot);
            if (ArrayUtil.isNotEmpty(historyLogDirRootLs)) {
                if (CollUtil.isEmpty(historyLogDirs)) {
                    for (File historyLogDir : historyLogDirRootLs) {
                        String name = FileUtil.getName(historyLogDir);
                        if (name.equals(".") || name.equals("..")) {
                            continue;
                        }
                        if (FileUtil.isDirectory(historyLogDir)) {
                            FileUtil.del(historyLogDir);
                        }
                    }
                } else {
                    for (File historyLogDir : historyLogDirRootLs) {
                        String name = FileUtil.getName(historyLogDir);
                        if (name.equals(".") || name.equals("..")) {
                            continue;
                        }
                        if (FileUtil.isDirectory(historyLogDir)) {
                            String historyLogDirCanonicalPath = FileUtil.getCanonicalPath(historyLogDir);
                            Optional<String> findFirst = historyLogDirs.stream().filter(item -> {
                                String itemCanonicalPath = FileUtil.getCanonicalPath(new File(item));
                                if (StrUtil.isBlank(itemCanonicalPath)) {
                                    return false;
                                }
                                return itemCanonicalPath.equals(historyLogDirCanonicalPath);
                            }).findFirst();
                            if (!findFirst.isPresent()) {
                                log.warn("删除多余Nginx历史日志文件，historyLogDir:" + historyLogDir + ",hostBindDomainData:" + hostBindDomainData);
                                FileUtil.del(historyLogDir);
                            }
                        }
                    }
                }
            }
        }
    }

    void makeHostBindDomainDataList(List<HostBindDomainData> doList) {
        int page = 1;
        int size = 200;
        PageInfo<Host> pageInfo = null;
        do {
            try {
                pageInfo = hostServiceImpl.findByWhere(page++, size);
            } catch (IOException e) {
            }
            if (pageInfo == null) {
                break;
            }

            List<Host> list = pageInfo.getList();
            if (CollUtil.isEmpty(list)) {
                break;
            }

            for (Host host : list) {
                List<HDomain> bindIndos = null;
                try {
                    bindIndos = domainServiceImpl.bindIndos(host.getId());
                } catch (IOException e) {
                }
                if (CollUtil.isNotEmpty(bindIndos)) {
                    List<HostBindDomainData.HostBindDomain> bindHDomainList = new ArrayList<>(bindIndos.size());
                    for (HDomain hDomain : bindIndos) {
                        String domainName = hDomain.getDomainName();
                        String makeAccessLog = null;
                        String makeErrorLog = null;
                        String makeNginxHistoryLogDir = null;
                        try {
                            makeAccessLog = nginxServer.makeAccessLog(domainName, host.getRandomCode());
                            makeErrorLog = nginxServer.makeErrorLog(domainName, host.getRandomCode());
                            makeNginxHistoryLogDir = nginxServer.makeNginxHistoryLogDir(domainName, host.getRandomCode());
                        } catch (IOException e) {
                        }
                        if (StrUtil.isBlank(makeAccessLog) || StrUtil.isBlank(makeErrorLog) || StrUtil.isBlank(makeNginxHistoryLogDir)) {
                            bindHDomainList = null;
                            break;
                        }

                        HostBindDomainData.HostBindDomain hbd = new HostBindDomainData.HostBindDomain();
                        hbd.setDomain(hDomain);
                        hbd.setAccessLog(makeAccessLog);
                        hbd.setErrorLog(makeErrorLog);
                        hbd.setHistoryLogDir(makeNginxHistoryLogDir);
                        bindHDomainList.add(hbd);
                    }
                    if (CollUtil.isNotEmpty(bindHDomainList)) {
                        HostBindDomainData hdbd = new HostBindDomainData();
                        hdbd.setHost(host);
                        hdbd.setBindHDomainList(bindHDomainList);
                        doList.add(hdbd);
                    }
                }
            }

        } while (pageInfo.isHasNextPage());
    }

    boolean nginxTest() {
        try {
            return nginxOperate.boolTest();
        } catch (IOException e) {
        }
        return false;
    }

    void nginxReload() {
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class HostBindDomainData {
        private Host host;
        private List<HostBindDomain> bindHDomainList;

        public List<String> logFilePath() {
            List<String> logFile = new ArrayList<>(bindHDomainList.size() * 2);
            List<HostBindDomain> listHostBindDomain = this.getBindHDomainList();
            for (HostBindDomain hostBindDomain : listHostBindDomain) {
                logFile.add(hostBindDomain.getAccessLog());
                logFile.add(hostBindDomain.getErrorLog());
            }
            return logFile;
        }

        public List<String> historyLogDir() {
            List<String> historyLogDir = new ArrayList<>(bindHDomainList.size());
            List<HostBindDomain> listHostBindDomain = this.getBindHDomainList();
            for (HostBindDomain hostBindDomain : listHostBindDomain) {
                historyLogDir.add(hostBindDomain.getHistoryLogDir());
            }
            return historyLogDir;
        }

        @Data
        @AllArgsConstructor
        @NoArgsConstructor
        public static class HostBindDomain {
            private HDomain domain;
            private String accessLog;
            private String errorLog;
            private String historyLogDir;
        }
    }

}
